using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Library;
using System;
using SkinnedModel;

namespace Rage
{
    public class Game1 :Game
    {
        GraphicsDeviceManager graphics;
        PhysicsActor mod;
        AnimationPlayer animationPlayer;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
           
        }

        protected override void LoadContent()
        {
            Engine.SetupEngine(graphics);
            ThirdPersonCamera camera = new ThirdPersonCamera();
            //FirstPersonCamera camera = new FirstPersonCamera();

            //camera.Position = new Vector3(20, 20f, 30);
            //camera.Position = new Vector3(0, 0, 0);
            
            KeyboardDevice keyboard = new KeyboardDevice();
            MouseDevice mouse = new MouseDevice();
            Engine.Services.AddService(typeof(Camera), camera);
            Engine.Services.AddService(typeof(Physics), new Physics());
            Engine.Services.AddService(typeof(MouseDevice), mouse);
            Engine.Services.AddService(typeof(KeyboardDevice), keyboard);

           Sky sky = new Sky(
               Engine.Content.Load<Model>("Content/Models/skyboxModel"),
               Engine.Content.Load<Effect>("Content/Shaders/skyboxShader"),
               Engine.Content.Load<TextureCube>("Content/Textures/cubeMap"),
               new Vector3(0, 0, 0), new Quaternion(0, 0, 0,0.5f), new Vector3(90, 90, 90));

            Terrain terrain = new Terrain(
                  Engine.Content.Load<Texture2D>("Content/Textures/heightmap"),
                  Engine.Content.Load<Texture2D>("Content/Textures/grass"));

            Water water = new Water(
                Engine.Content.Load<Effect>("Content/Shaders/waterEffect"),
                Engine.Content.Load<TextureCube>("Content/Textures/cubeMap"));

            Model model = Engine.Content.Load<Model>("Content/Models/actor");
            BoxObject bo = new BoxObject(new Vector3(1, 1, 1), new Vector3(50, 5, 50), Vector3.Zero);
            bo.Mass = 50;
            mod = new PhysicsActor(model, bo);
            mod.DrawOrder = 2;
            camera.Position = new Vector3(0,5.0f, -5.0f);

            Model currentModel = mod.model;

            SkinningData skinningData = currentModel.Tag as SkinningData;

            if (skinningData == null)
                throw new InvalidOperationException
                    ("This model does not contain a SkinningData tag.");

            animationPlayer = new AnimationPlayer(skinningData);

            AnimationClip clip = skinningData.AnimationClips["Idle"];

            animationPlayer.StartClip(clip);
        }



        protected override void Update(GameTime gameTime)
        {
            
            Engine.Update(gameTime);
            KeyboardDevice keyboard = Engine.Services.GetService<KeyboardDevice>();
            MouseDevice mouse = Engine.Services.GetService<MouseDevice>();
            //FirstPersonCamera cam = (FirstPersonCamera)Engine.Services.GetService<Camera>();
            ThirdPersonCamera cam = (ThirdPersonCamera)Engine.Services.GetService<Camera>();

            cam.RotateTranslate(new Vector3(0, mouse.Delta.X * -.002f, 0), Vector3.Zero,mod.Position,mod.Rotation, new Vector3(0, 5, -15));
            
            cam.Target = mod.Position;
            Matrix[] transforms = new Matrix[mod.model.Bones.Count];
            mod.model.CopyAbsoluteBoneTransformsTo(transforms);
            Matrix world = Matrix.Identity * Matrix.CreateRotationY(0f) * Matrix.CreateTranslation(mod.Position);
            animationPlayer.Update(gameTime.ElapsedGameTime, true,world);
            UpdateActorPosition();

            //activate to use first person camera tu fly around
            /*Vector3 inputModifier = new Vector3(
                (keyboard.IsKeyDown(Keys.A) ? -10 : 0) + (keyboard.IsKeyDown(Keys.D) ? 10 : 0),
                (keyboard.IsKeyDown(Keys.Q) ? -10 : 0) + (keyboard.IsKeyDown(Keys.E) ? 10 : 0),
                (keyboard.IsKeyDown(Keys.W) ? -10 : 0) + (keyboard.IsKeyDown(Keys.S) ? 10 : 0)
            );

            cam.RotateTranslate(new Vector3(mouse.Delta.Y * -.002f, mouse.Delta.X * -.002f, 0), inputModifier * .5f);*/
            /*if (mouse.WasButtonPressed(MouseButtons.Left))
            {
                PhysicsActor act = new PhysicsActor(
                    Engine.Content.Load<Model>("Content/Models/ig_box"),
                    new BoxObject(new Vector3(.5f), mod.Position, Vector3.Zero));

                act.Scale = new Vector3(.5f);
                act.PhysicsObject.Mass = 1000;

                Vector3 dir = cam.Target - cam.Position;
                dir.Normalize();

                act.PhysicsObject.Velocity = dir * 10;
            }*/

            if (keyboard.WasKeyPressed(Keys.Escape))
                this.Exit();
           
           
            base.Update(gameTime);
        }

        void UpdateActorPosition()
        {
            KeyboardDevice keyboard = Engine.Services.GetService<KeyboardDevice>();
            MouseDevice mouse = Engine.Services.GetService<MouseDevice>();
            GamePadState currentState = GamePad.GetState(PlayerIndex.One);
            //FirstPersonCamera cam = (FirstPersonCamera)Engine.Services.GetService<Camera>();
            ThirdPersonCamera cam = (ThirdPersonCamera)Engine.Services.GetService<Camera>();
            float forwardSpeed = 20f / 60f;
            mod.Rotation = cam.Rotation;

            if (keyboard.IsKeyDown(Keys.A) ||
                (currentState.DPad.Left == ButtonState.Pressed))
            {
                Vector3 v = new Vector3(forwardSpeed, 0, 0);
                v = Vector3.Transform(v, mod.Rotation);
                mod.Position = new Vector3(mod.Position.X + v.X, mod.Position.Y, mod.Position.Z + v.Z);
            }

            if (keyboard.IsKeyDown(Keys.D) ||
                (currentState.DPad.Right == ButtonState.Pressed))
            {
                Vector3 v = new Vector3(-forwardSpeed, 0, 0);
                v = Vector3.Transform(v, mod.Rotation);
                mod.Position = new Vector3(mod.Position.X + v.X, mod.Position.Y, mod.Position.Z + v.Z);
            }

            if (keyboard.IsKeyDown(Keys.W) ||
                (currentState.DPad.Up == ButtonState.Pressed))
            {
                Vector3 v = new Vector3(0, 0, forwardSpeed);
                v = Vector3.Transform(v, mod.Rotation);
                mod.Position = new Vector3(mod.Position.X + v.X, mod.Position.Y, mod.Position.Z + v.Z);
            }

            if (keyboard.IsKeyDown(Keys.S) ||
                (currentState.DPad.Down == ButtonState.Pressed))
            {
                Vector3 v = new Vector3(0, 0, -forwardSpeed);
                v = Vector3.Transform(v, mod.Rotation);
                mod.Position = new Vector3(mod.Position.X +v.X,mod.Position.Y, mod.Position.Z +v.Z);
            }
        }

        protected override void Draw(GameTime gameTime)
        {
            Matrix[] bones = animationPlayer.GetSkinTransforms();
            Matrix view = Engine.Services.GetService<Camera>().View;
            //Matrix[] transforms = new Matrix[currentModel.Bones.Count];
            //currentModel.CopyAbsoluteBoneTransformsTo(transforms);
          
            Matrix projection = Engine.Services.GetService<Camera>().Projection;

            foreach (ModelMesh mesh in mod.model.Meshes)
            {
                foreach (Effect effect in mesh.Effects)
                {
                    //Matrix world = transforms[mesh.ParentBone.Index] * Matrix.CreateRotationY(0.0f) * Matrix.CreateTranslation(Vector3.Zero);
                    //effect.Parameters["World"].SetValue(world);
                    effect.Parameters["Bones"].SetValue(bones);
                    effect.Parameters["View"].SetValue(view);
                    effect.Parameters["Projection"].SetValue(projection);
                }

                mesh.Draw();
            }

            //Engine.GraphicsDevice.RenderState.FillMode = FillMode.WireFrame;
            Engine.Draw(gameTime, ComponentType.All);
            base.Draw(gameTime);
        }
    }
}
